package com.imooc.course.server.utils;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.vod.model.v20170321.*;

import java.io.File;
import java.io.InputStream;
import java.util.Base64;

public class VodUtil {

    public class Config {
        public String regionId;
        public String accessKeyId;
        public String accessKeySecret;
        public String fileName;
        public String title;
        public String desc;
        public String tags;//可设置多个标签，示例：request.setTags("tags,tags");
        public String coverURL;
        public Long cateId;
        public String templateGroupId;
        public String workflowId;
        public String storageLocation;
        public String appId;
        public Integer sysReadTimeout;
        public Integer sysConnectTimeout;
    }

    public class ExecuteUpload {

        private DefaultAcsClient vodClient;
        private String videoId;

        /**
         * 初始化VOD客户端
         *
         * @param regionId
         * @param accessKeyId
         * @param accessKeySecret
         * @return DefaultAcsClient
         * @throws ClientException
         */
        public DefaultAcsClient initVodClient(String regionId, String accessKeyId, String accessKeySecret) throws ClientException {
            // 根据点播接入服务所在的Region填写，例如：接入服务在上海，则填cn-shanghai；
            // 其他区域请参见:登录阿里云-点播控制台/存储管理/存储管理/存储地址
            DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
            DefaultAcsClient client = new DefaultAcsClient(profile);
            return client;
        }

        /**
         * 获取视频上传地址和凭证
         *
         * @param vodClient
         * @return CreateUploadVideoResponse
         * @throws ClientException
         */
        public CreateUploadVideoResponse createUploadVideo(DefaultAcsClient vodClient, Config config) throws ClientException {
            CreateUploadVideoRequest request = new CreateUploadVideoRequest();

            if (config.fileName == null) {
                config.fileName = "vod_test.mp4";
            }
            //设置文件名.扩展名
            request.setFileName(config.fileName);

            if (config.title == null) {
                config.title = "this is title";

            }
            //标题
            request.setTitle(config.title);

            if (config.desc != null) {
                //视频描述，UTF-8编码，长度不超过1024个字符
                request.setDescription(config.desc);
            }
            if (config.tags != null) {
                //视频标签，多个用逗号分割，示例：request.setTags("tags,tags");
                request.setTags(config.tags);
            }
            if (config.coverURL != null) {
                //自定义视频封面的URL地址。默认值："http://vod.aliyun.com/test_cover_url.jpg"
                request.setCoverURL(config.coverURL);
            }
            if (config.cateId != null) {
                //视频分类ID。-1代表不选择分类
                request.setCateId(config.cateId);
            }
            if (config.templateGroupId != null) {
                //转码模板组ID。
                request.setTemplateGroupId(config.templateGroupId);
            }
            if (config.workflowId != null) {
                //工作流ID。
                request.setWorkflowId(config.workflowId);
            }
            if (config.storageLocation != null) {
                //存储地址。//out-****.oss-cn-shanghai.aliyuncs.com
                //不设置即为默认使用华东2(上海)的储存地址，显式设置上海的储存地址也报错，未解决。
                //request.setStorageLocation("outin-d775cc094a5c11eba6c400163e021072.oss-cn-shenzhen.aliyuncs.com");
                request.setStorageLocation(config.storageLocation);
            }
            if (config.appId != null) {
                //应用ID。默认取值：app-1000000。使用说明，请参见多应用。
                request.setAppId(config.appId);
            }
            if (config.sysReadTimeout != null && config.sysConnectTimeout !=null) {
                //设置请求超时时间
                request.setSysReadTimeout(config.sysReadTimeout);
                request.setSysConnectTimeout(config.sysConnectTimeout);
            } else {
                request.setSysReadTimeout(1000);
                request.setSysConnectTimeout(1000);
            }
            return vodClient.getAcsResponse(request);
        }

        /**
         * 使用上传凭证和地址初始化OSS客户端（注意需要先Base64解码并Json Decode再传入）
         *
         * @param uploadAuth
         * @param uploadAddress
         * @return
         */
        public OSSClient initOssClient(JSONObject uploadAuth, JSONObject uploadAddress) {
            String endpoint = uploadAddress.getString("Endpoint");
            String accessKeyId = uploadAuth.getString("AccessKeyId");
            String accessKeySecret = uploadAuth.getString("AccessKeySecret");
            String securityToken = uploadAuth.getString("SecurityToken");
            OSSClient oss = (OSSClient) new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);
            return oss;
            //new OSSClient()构造函数即将过时
            //return new OSSClient(endpoint, accessKeyId, accessKeySecret, securityToken);
        }

        /**
         * 上传本地文件
         *
         * @param ossClient
         * @param uploadAddress
         * @param localFile
         */
        public void uploadLocalFile(OSSClient ossClient, JSONObject uploadAddress, String localFile) {
            String bucketName = uploadAddress.getString("Bucket");
            String objectName = uploadAddress.getString("FileName");
            File file = new File(localFile);
            ossClient.putObject(bucketName, objectName, file);

        /* 经测试并提交工单咨询官方，已验证：视频点播不支持追加上传
        // 追加上传
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType("text/plain");
        AppendObjectRequest request = new AppendObjectRequest(bucketName, objectName, file, meta);
        request.setPosition(0L);
        ossClient.appendObject(request);*/
        }

        /**
         * 上传本地文件
         *
         * @param ossClient
         * @param uploadAddress
         * @param inputStream
         */
        public void uploadLocalFile(OSSClient ossClient, JSONObject uploadAddress, InputStream inputStream) {
            String bucketName = uploadAddress.getString("Bucket");
            String objectName = uploadAddress.getString("FileName");
            ossClient.putObject(bucketName, objectName, inputStream);
        }

        /**
         * 刷新上传凭证
         *
         * @param vodClient
         * @return RefreshUploadVideoResponse
         * @throws ClientException
         */
        public RefreshUploadVideoResponse refreshUploadVideo(DefaultAcsClient vodClient) throws ClientException {
            RefreshUploadVideoRequest request = new RefreshUploadVideoRequest();
            request.setAcceptFormat(FormatType.JSON);
            request.setVideoId("VideoId");
            //设置请求超时时间
            request.setSysReadTimeout(1000);
            request.setSysConnectTimeout(1000);
            return vodClient.getAcsResponse(request);
        }

        public DefaultAcsClient getVodClient() {
            return vodClient;
        }

        private void setVodClient(DefaultAcsClient vodClient) {
            this.vodClient = vodClient;
        }

        public String getVideoId() {
            return videoId;
        }

        private void setVideoId(String videoId) {
            this.videoId = videoId;
        }
    }

    /**
     * 上传至阿里云视频点播服务
     * @param executeUpload
     * @param config
     * @param inputStream
     */
    public void executeUploadToApsaraVideo(ExecuteUpload executeUpload, Config config, InputStream inputStream) {
        try {
            // 初始化VOD客户端
            DefaultAcsClient vodClient = executeUpload.initVodClient(config.regionId, config.accessKeyId, config.accessKeySecret);
            executeUpload.setVodClient(vodClient);

            //获取上传地址和凭证
            CreateUploadVideoResponse createUploadVideoResponse = executeUpload.createUploadVideo(vodClient, config);

            // 执行成功会返回VideoId、UploadAddress和UploadAuth
            String videoId = createUploadVideoResponse.getVideoId();
            executeUpload.setVideoId(videoId);

            //需要解码上传地址和上传凭证
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] auth = decoder.decode(createUploadVideoResponse.getUploadAuth());
            byte[] address = decoder.decode(createUploadVideoResponse.getUploadAddress());
            JSONObject uploadAuth = JSONObject.parseObject(auth, JSONObject.class);
            JSONObject uploadAddress = JSONObject.parseObject(address, JSONObject.class);

            /*
            官方提供的转码方式，decodeBase64(base64解码)需要自己选择解码的类，这里使用了java.util.Base64
            JSONObject uploadAuth = JSONObject.parseObject(decodeBase64(createUploadVideoResponse.getUploadAuth()));
            JSONObject uploadAddress = JSONObject.parseObject(decodeBase64(createUploadVideoResponse.getUploadAddress()));
             */

            // 使用UploadAuth和UploadAddress初始化OSS客户端
            OSSClient ossClient = executeUpload.initOssClient(uploadAuth, uploadAddress);

            // 上传文件，注意是同步上传会阻塞等待，耗时与文件大小和网络上行带宽有关
            executeUpload.uploadLocalFile(ossClient, uploadAddress, inputStream);

            System.out.println("本地文件上传成功, VideoId : " + videoId);
            System.out.println("Put local file succeed, VideoId : " + videoId);

            // 关闭OSSClient。
            ossClient.shutdown();

        } catch (Exception e) {
            System.out.println("本地文件上传失败, ErrorMessage : " + e.getLocalizedMessage());
            System.out.println("Put local file fail, ErrorMessage : " + e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    /**
     * 获取源文件信息
     * @param client 发送请求客户端
     * @return GetMezzanineInfoResponse 获取源文件信息响应数据
     * @throws Exception
     */
    public GetMezzanineInfoResponse getMezzanineInfo(DefaultAcsClient client,String videoId) throws Exception {
        GetMezzanineInfoRequest request = new GetMezzanineInfoRequest();
        request.setVideoId(videoId);
        //源片下载地址过期时间
        request.setAuthTimeout(3600L);
        return client.getAcsResponse(request);
        //使用示例：
        //getMezzanineInfoResponse.getMezzanine().getVideoId();
        //getMezzanineInfoResponse.getMezzanine().getFileURL();
        //getMezzanineInfoResponse.getMezzanine().getSize();
    }

    /**
     * 获取播放凭证函数
     * @param client
     * @return GetVideoPlayAuthResponse
     * @throws Exception
     */
    public GetVideoPlayAuthResponse getVideoPlayAuth(DefaultAcsClient client, String videoId) throws Exception {
        GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
        request.setVideoId(videoId);
        return client.getAcsResponse(request);
        //获取播放凭证
        //getVideoPlayAuthResponse.getPlayAuth();
        //VideoMeta信息
        //getVideoPlayAuthResponse.getVideoMeta().getTitle()
    }

    /**
     * 删除视频
     * @param client 发送请求客户端
     * @return DeleteVideoResponse 删除视频响应数据
     * @throws Exception
     */
    public DeleteVideoResponse deleteVideo(DefaultAcsClient client, String videoIds) throws Exception {
        DeleteVideoRequest request = new DeleteVideoRequest();
        //支持传入多个视频ID，多个用逗号分隔request.setVideoIds("videoId1,videoId2");
        request.setVideoIds(videoIds);
        return client.getAcsResponse(request);
    }

    //程序入口，触发装置 (测试用)
    public static void main(String[] argv) {
        ExecuteUpload executeUpload = new VodUtil().new ExecuteUpload();
        Config config = new VodUtil().new Config();
        config.fileName = "vod_test.mp4";
        config.title = "this is title";
        config.desc = "this is desc";
        //服务区域
        String regionId = "cn-shenzhen";
        //您的AccessKeyId
        String accessKeyId = "LTAI4G7AgU7ybeettziWhojk";
        //您的AccessKeySecret
        String accessKeySecret = "XFiWvy1a6bjuBXp6Z5Hqx6L3kjEuFJ";
        //需要上传到VOD的本地视频文件的完整路径，需要包含文件扩展名
        String localFile = "D:\\IDEA\\imoocWorkSpace\\course\\admin\\public\\static\\image\\section-video\\test1.mp4";
        try {
            // 初始化VOD客户端并获取上传地址和凭证
            DefaultAcsClient vodClient = executeUpload.initVodClient(regionId, accessKeyId, accessKeySecret);
            CreateUploadVideoResponse createUploadVideoResponse = executeUpload.createUploadVideo(vodClient,config);
            // 执行成功会返回VideoId、UploadAddress和UploadAuth
            String videoId = createUploadVideoResponse.getVideoId();

            //需要解码上传地址和上传凭证
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] auth = decoder.decode(createUploadVideoResponse.getUploadAuth());
            byte[] address = decoder.decode(createUploadVideoResponse.getUploadAddress());
            JSONObject uploadAuth = JSONObject.parseObject(auth, JSONObject.class);
            JSONObject uploadAddress = JSONObject.parseObject(address, JSONObject.class);

            //官方提供的转码方式，decodeBase64(base64解码)需要自己选择解码的类，这里使用了java.util.Base64
            //JSONObject uploadAuth = JSONObject.parseObject(decodeBase64(createUploadVideoResponse.getUploadAuth()));
            //JSONObject uploadAddress = JSONObject.parseObject(decodeBase64(createUploadVideoResponse.getUploadAddress()));

            // 使用UploadAuth和UploadAddress初始化OSS客户端
            OSSClient ossClient = executeUpload.initOssClient(uploadAuth, uploadAddress);
            // 上传文件，注意是同步上传会阻塞等待，耗时与文件大小和网络上行带宽有关
            executeUpload.uploadLocalFile(ossClient, uploadAddress, localFile);
            System.out.println("本地文件上传成功, VideoId : " + videoId);
            System.out.println("Put local file succeed, VideoId : " + videoId);
            // 关闭OSSClient。
            ossClient.shutdown();
        } catch (Exception e) {
            System.out.println("本地文件上传失败, ErrorMessage : " + e.getLocalizedMessage());
            System.out.println("Put local file fail, ErrorMessage : " + e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

}
